﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Text;
using System.Threading;

namespace Walson.IO.Ports
{
    public partial class SerialPort : System.IO.Ports.SerialPort
    {
        bool _Exiting = false;
        bool _Running = false;

        List<string> _LastPortNames = new List<string>(System.IO.Ports.SerialPort.GetPortNames());

        /// <summary>
        /// 端口列表变化（如 USB 转串口被拔出）
        /// </summary>
        /// <param name="sender">事件的发送方</param>
        /// <param name="e">参数</param>
        public delegate void PortListChangedEventHandler(object sender, EventArgs e);
        /// <summary>
        /// 端口列表变化事件
        /// </summary>
        public event PortListChangedEventHandler PortListChanged;
        protected void onPortListChanged()
        {
            if (this.PortListChanged != null)
            {
                this.PortListChanged(this, new EventArgs());
            }
        }

        /// <summary>
        /// 端口意外丢失（如 USB 转串口被拔出）
        /// </summary>
        /// <param name="sender">事件的发送方</param>
        /// <param name="e">参数</param>
        public delegate void PortLostEventHandler(object sender, EventArgs e);
        /// <summary>
        /// 端口意外丢失事件
        /// </summary>
        public event PortLostEventHandler PortLost;
        protected void onPortLost()
        {
            if (this.PortLost != null)
            {
                this.PortLost(this, new EventArgs());
            }
        }



        public delegate void DataReceivedHandler(object sender, EventArgs e);
        /// <summary>
        /// 表示数据接收事件的方法
        /// </summary>
        public new event DataReceivedHandler DataReceived;

        
        /// <summary>
        /// 表示串行端口资源
        /// </summary>
        public SerialPort()
        {
            InitializeComponent();
            BeginPortNameCheck();
            base.DataReceived += SerialPort_DataReceived;
        }


        /// <summary>
        /// 表示串行端口资源
        /// </summary>
        /// <param name="container"></param>
        public SerialPort(IContainer container)
        {
            container.Add(this);
            BeginPortNameCheck();
            InitializeComponent();

            base.DataReceived += SerialPort_DataReceived;
        }

        /// <summary>
        /// 打开一个新的串行端口连接
        /// </summary>
        public new void Open()
        {
            _Running = true;
            base.Open();
        }

        /// <summary>
        /// 关闭端口连接，将 System.IO.Ports.SerialPort.IsOpen 属性设置为 false，并释放内部 System.IO.Stream 对象
        /// </summary>
        public new void Close()
        {
            _Running = false;
            base.Close();
        }


        void SerialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            if (_Exiting || _Running==false)
                return;

            if(this.DataReceived!=null)
            {
                this.DataReceived(this, e);
            }
        }

        private void BeginPortNameCheck()
        {
            Thread thd = new Thread(new ThreadStart(thdCheckPortNames));
            thd.IsBackground = true;
            thd.Start();
        }

        private void thdCheckPortNames()
        {
            List<string> ports = new List<string>();
            while(_Exiting==false && _Running)
            {
                ports.Clear();
                ports.AddRange(System.IO.Ports.SerialPort.GetPortNames());

                if (_Running)
                {                
                    if (!ports.Contains(this.PortName))
                    {
                        this.Close();
                        onPortLost();
                    }
                }

                if(_LastPortNames.Count!=ports.Count)
                {
                    onPortListChanged();
                    _LastPortNames.Clear();
                    _LastPortNames.AddRange(ports);
                }
                else
                {
                    foreach(string str in _LastPortNames)
                    {
                        if(!ports.Contains(str))
                        {
                            onPortListChanged();
                            _LastPortNames.Clear();
                            _LastPortNames.AddRange(ports);
                            break;
                        }
                    }
                }

                Thread.Sleep(100);
            }
        }

        void Dispose()
        {
            _Exiting = true;
            base.DataReceived -= SerialPort_DataReceived;
            base.Dispose();
        }

        /// <summary> 
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            _Exiting = true;
            base.DataReceived -= SerialPort_DataReceived;

            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}
